﻿namespace _11_委托;

// 声明一个委托
internal delegate void MyDelegate();

internal delegate void MyDelegate2(int x, int y);

internal delegate int Arithm(int x, int y);

internal delegate void OnFiveHandler(object sender, EventArgs e);

internal class FEvent
{
    public event OnFiveHandler FiveEvent;

    public void OnFiveEvent()
    {
        // 等同于if(FiveEvent != null) { FiveEvent(this, EventArgs.Empty);}
        FiveEvent?.Invoke(this, EventArgs.Empty);
    }
}

public delegate void OnTenHandler(object sender, TenEventArgs e);

public class TenEventArgs : EventArgs
{
    public int count;
    public DateTime time;

    public TenEventArgs(int count, DateTime time)
    {
        this.count = count;
        this.time = time;
    }
}

public class TEvent
{
    public event OnTenHandler TenEvent;

    public void OnTenEvent(TenEventArgs e)
    {
        TenEvent(this, e);
    }
}

public class Oper
{
    public static void Add(int x, int y)
    {
        Console.WriteLine($"{x} + {y} = {x + y}");
    }

    public static void Sub(int x, int y)
    {
        Console.WriteLine($"{x} - {y} = {x - y}");
    }
}

public delegate void NameDelegate(string msg);

public class Person
{
    public string firstName;
    public string secondName;

    public Person(string firstName, string secondName)
    {
        this.firstName = firstName;
        this.secondName = secondName;
    }

    public void ShowFirstName(string msg)
    {
        Console.WriteLine(msg + firstName);
    }

    public void ShowSecondName(string msg)
    {
        Console.WriteLine(msg + secondName);
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        #region 0_委托概念

        // 委托是一种类型安全的函数指针，它表示一个引用方法, 而不是一个引用对象。

        #endregion

        #region 1_委托的使用

        //// 1.new关键字创建委托
        //var md = new MyDelegate(MyCallBack);
        //md();
        //// 2. 直接实现委托
        //MyDelegate md2 = MyCallBack;
        //md2();

        #endregion

        #region 2_委托指向不同的方法

        //var per = new Person("Fabius", "Maximus");

        //var nDelegate = new NameDelegate(per.ShowFirstName);
        //nDelegate("Call 1: ");

        //nDelegate = new NameDelegate(per.ShowSecondName);
        //nDelegate("Call 2: ");

        #endregion

        #region 3_多播委托: 拥有对多个方法的引用的委托, 该委托必须仅包含返回void的方法, 否则将会存在运行时异常

        //var del = new MyDelegate2(Oper.Add);
        //del += Oper.Sub; // 先增加这个委托,可执行添加的方法, 也就是Add + Sub
        //del(1, 2); 
        //del -= Oper.Sub; // 然后删除该委托 只执行Add
        //del(1, 2);

        #endregion

        #region 4_匿名方法

        //MyDelegate del = delegate
        //{
        //    Console.WriteLine("匿名方法");
        //}; // 匿名方法

        //del();

        #endregion

        #region 5_委托作为方法参数

        //DoOperation(10, 20, Multiply);
        //DoOperation(10, 20, Divide);

        #endregion

        #region 6_事件

        //// .Net Framework中事件是使用委托来实现的,其具有两个参数: 引发事件的源和事件参数(数据)
        //var fe = new FEvent();
        //fe.FiveEvent += new OnFiveHandler(Callback);
        //var random = new Random();
        //for (int i = 0; i < 50; i++)
        //{
        //    int rd = random.Next(1, 6);
        //    Console.WriteLine($"{rd}");
        //    if (rd == 5)
        //    {
        //        fe.OnFiveEvent();
        //    }
        //}

        #endregion

        #region 7_复杂事件委托

        //int count = 0;
        //TenEventArgs tenArgs;

        //var fe = new TEvent();
        //fe.TenEvent += new OnTenHandler(CallBack2);

        //var random = new Random();

        //for (int i = 0; i < 10; i++)
        //{
        //    int rn = random.Next(6);

        //    Console.WriteLine(rn);

        //    if (rn == 10)
        //    {
        //        count++;
        //        tenArgs = new TenEventArgs(count, DateTime.Now);
        //        fe.OnTenEvent(tenArgs);
        //    }
        //}

        #endregion

        #region 8_预定义的委托

        // 1. 动作委托: Action, 用于执行一个动作
        // 1.1 无参数的动作委托
        var ack = ShowMessageAction;
        ack();
        // 1.2 有参数的动作委托
        var ack2 = ShowMessage;
        ack2("Action 设计");

        // 2. 谓词委托 Predicate, 用于判断一个条件是否成立
        Predicate<int> predicate = biggerThanZero;
        predicate(1); // 
        var list = new List<int> { -2, -3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        var positiveNumbers = list.FindAll(predicate);
        Console.WriteLine(string.Join(",", positiveNumbers));

        #endregion
    }

    private static bool biggerThanZero(int x)
    {
        var b = x > 0;
        Console.WriteLine($"{x} > 0: {b}");
        return b;
    }

    private static void ShowMessageAction()
    {
        Console.WriteLine("Action委托");
    }

    private static void ShowMessage(string msg)
    {
        Console.WriteLine(msg);
    }

    private static void MyCallBack()
    {
        Console.WriteLine("回调函数");
    }

    private static void DoOperation(int x, int y, Arithm del)
    {
        var z = del(x, y);
        Console.WriteLine($"{x} {del.Method.Name} {y} = {z}");
    }

    private static int Multiply(int x, int y)
    {
        return x * y;
    }

    private static int Divide(int x, int y)
    {
        return x / y;
    }

    private static void Callback(object sender, EventArgs e)
    {
        Console.WriteLine("回调函数");
    }

    private static void CallBack2(object sender, TenEventArgs e)
    {
        Console.WriteLine("Ten event {0} occurred at {1}",
            e.count, e.time);
    }
}